{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "N7ITxKLUkX0v"
      },
      "source": [
        "##### Copyright 2020 The TensorFlow Authors."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "cellView": "form",
        "id": "yOYx6tzSnWQ3"
      },
      "outputs": [],
      "source": [
        "#@title Licensed under the Apache License, Version 2.0 (the \"License\");\n",
        "# you may not use this file except in compliance with the License.\n",
        "# You may obtain a copy of the License at\n",
        "#\n",
        "# https://www.apache.org/licenses/LICENSE-2.0\n",
        "#\n",
        "# Unless required by applicable law or agreed to in writing, software\n",
        "# distributed under the License is distributed on an \"AS IS\" BASIS,\n",
        "# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n",
        "# See the License for the specific language governing permissions and\n",
        "# limitations under the License."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "6xgB0Oz5eGSQ"
      },
      "source": [
        "# グラフと tf.function の基礎"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "w4zzZVZtQb1w"
      },
      "source": [
        "<table class=\"tfo-notebook-buttons\" align=\"left\">\n",
        "  <td>     <a target=\"_blank\" href=\"https://www.tensorflow.org/guide/intro_to_graphs\" class=\"\"><img src=\"https://www.tensorflow.org/images/tf_logo_32px.png\">TensorFlow.org で表示</a>   </td>\n",
        "  <td>     <a target=\"_blank\" href=\"https://colab.research.google.com/github/tensorflow/docs-l10n/blob/master/site/ja/guide/intro_to_graphs.ipynb\" class=\"\"><img src=\"https://www.tensorflow.org/images/colab_logo_32px.png\">Google Colab で実行</a>   </td>\n",
        "  <td>     <a target=\"_blank\" href=\"https://github.com/tensorflow/docs-l10n/blob/master/site/ja/guide/intro_to_graphs.ipynb\" class=\"\"><img src=\"https://www.tensorflow.org/images/GitHub-Mark-32px.png\">GitHub でソースを表示</a>   </td>\n",
        "  <td>     <a href=\"https://storage.googleapis.com/tensorflow_docs/docs-l10n/site/ja/guide/intro_to_graphs.ipynb\" class=\"\"><img src=\"https://www.tensorflow.org/images/download_logo_32px.png\">ノートブックをダウンロード</a>   </td>\n",
        "</table>"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "RBKqnXI9GOax"
      },
      "source": [
        "## 概要\n",
        "\n",
        "このガイドは、TensorFlow の仕組みを説明するために、TensorFlow と Keras 基礎を説明します。今すぐ Keras に取り組みたい方は、[Keras のガイド一覧](keras/)を参照してください。\n",
        "\n",
        "このガイドでは、グラフ取得のための単純なコード変更、格納と表現、およびモデルの高速化とエクスポートを行うための使用方法について、TensorFlow の中核的な仕組みを説明します。\n",
        "\n",
        "注意: TensorFlow 1.x のみの知識をお持ちの場合は、このガイドでは、非常に異なるグラフビューが紹介されています。\n",
        "\n",
        "**ここでは、`tf.function` を使って Eager execution から Graph execution に切り替える方法を概説しています。** より詳しい `tf.function` の仕様については、<a href=\"function\" data-md-type=\"link\">`tf.function` ガイド</a>をご覧ください。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "v0DdlfacAdTZ"
      },
      "source": [
        "### グラフとは？\n",
        "\n",
        "前の 3 つのガイドでは、TensorFlow を **Eager** で実行する方法を紹介しました。つまり、TensorFlow 演算は、Python によって演算ごとに実行され、Python に結果を戻しました。\n",
        "\n",
        "Eager execution には特有のメリットがいくつかありますが、Graph execution では Python 外への移植が可能になり、より優れたパフォーマンスを得られる傾向にあります。**Graph execution** では、テンソルの計算は *TensorFlow グラフ*（`tf.Graph` または単に「graph」とも呼ばれます）として実行されます。\n",
        "\n",
        "**グラフとは、計算のユニットを表す一連の `tf.Operation` オブジェクトと、演算間を流れるデータのユニットを表す `tf.Tensor` オブジェクトを含むデータ構造です。** `tf.Graph` コンテキストで定義されます。これらのグラフはデータ構造であるため、元の Python コードがなくても、保存、実行、および復元することができます。\n",
        "\n",
        "**グラフとは、計算のユニットを表す一連の `tf.Operation` オブジェクトと、演算間を流れるデータのユニットを表す `tf.Tensor` オブジェクトを含むデータ構造です。** `tf.Graph` コンテキストで定義されます。これらのグラフはデータ構造であるため、元の Python コードがなくても、保存、実行、および復元することができます。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "FvQ5aBuRGT1o"
      },
      "source": [
        "<img alt=\"単純なTensorFlowグラフ\" src=\"./images/intro_to_graphs/two-layer-network.png\">"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DHpY3avXGITP"
      },
      "source": [
        "### グラフのメリット\n",
        "\n",
        "グラフを使用すると、柔軟性が大幅に向上し、モバイルアプリケーション。組み込みデバイス、バックエンドサーバーといった Python インタプリタのない環境でも TensorFlow グラフを使用できます。TensorFlow は、Python からエクスポートされた場合に、保存されるモデルの形式としてグラフを使用します。\n",
        "\n",
        "また、グラフは最適化を簡単に行えるため、コンパイラは次のような変換を行えます。\n",
        "\n",
        "- 計算に定数ノードを畳み込むで、テンソルの値を統計的に推論します*（「定数畳み込み」）*。\n",
        "- 独立した計算のサブパートを分離し、スレッドまたはデバイスに分割します。\n",
        "- 共通部分式を取り除き、算術演算を単純化します。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "o1x1EOD9GjnB"
      },
      "source": [
        "これやほかの高速化を実行する [Grappler](./graph_optimization.ipynb) という総合的な最適化システムがあります。\n",
        "\n",
        "まとめると、グラフは非常に便利なもので、**複数のデバイス**で、TensorFlow の**高速化**、**並列化**、および効率化を期待することができます。\n",
        "\n",
        "ただし、便宜上、Python で機械学習モデル（またはその他の計算）を定義した後、必要となったときに自動的にグラフを作成することをお勧めします。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "pSZebVuWxDXu"
      },
      "source": [
        "## グラフを利用する\n",
        "\n",
        "TensorFlow では、`tf.function` を直接呼出しまたはデコレータとして使用し、グラフを作成して実行します。`tf.function` は通常の関数を入力として取り、`Function` を返します。<strong data-md-type=\"double_emphasis\">`Function` は、Python 関数から TensorFlow グラフを構築する Python コーラブルです。`Function` は 相当する Python 関数と同様に使用します。</strong>\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "goZwOXp_xyQj"
      },
      "outputs": [],
      "source": [
        "import tensorflow as tf\n",
        "import timeit\n",
        "from datetime import datetime"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "HKbLeJ1y0Umi"
      },
      "outputs": [],
      "source": [
        "# Define a Python function\n",
        "def function_to_get_faster(x, y, b):\n",
        "  x = tf.matmul(x, y)\n",
        "  x = x + b\n",
        "  return x\n",
        "\n",
        "# Create a `Function` object that contains a graph\n",
        "a_function_that_uses_a_graph = tf.function(function_to_get_faster)\n",
        "\n",
        "# Make some tensors\n",
        "x1 = tf.constant([[1.0, 2.0]])\n",
        "y1 = tf.constant([[2.0], [3.0]])\n",
        "b1 = tf.constant(4.0)\n",
        "\n",
        "# It just works!\n",
        "a_function_that_uses_a_graph(x1, y1, b1).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PNvuAYpdrTOf"
      },
      "source": [
        "一方、`Function` は、TensorFlow 演算を使って記述する通常の関数のように見えます。ただし、[その根底では](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/eager/def_function.py)*非常に異なります*。`Function` は**1 つの API の背後で[複数の `tf.Graph` をカプセル化しています](#polymorphism_one_function_many_graphs)。**`Function` が速度やデプロイ可能性といった[Graph execution のメリット](#the_benefits_of_graphs)を提供できるのはこのためです。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "MT7U8ozok0gV"
      },
      "source": [
        "`tf.function` は関数と*それが呼び出すその他すべての関数に次のように適用します*。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "rpz08iLplm9F"
      },
      "outputs": [],
      "source": [
        "def inner_function(x, y, b):\n",
        "  x = tf.matmul(x, y)\n",
        "  x = x + b\n",
        "  return x\n",
        "\n",
        "# Use the decorator\n",
        "@tf.function\n",
        "def outer_function(x):\n",
        "  y = tf.constant([[2.0], [3.0]])\n",
        "  b = tf.constant(4.0)\n",
        "\n",
        "  return inner_function(x, y, b)\n",
        "\n",
        "# Note that the callable will create a graph that\n",
        "# includes inner_function() as well as outer_function()\n",
        "outer_function(tf.constant([[1.0, 2.0]])).numpy()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "P88fOr88qgCj"
      },
      "source": [
        "TensorFlow 1.x を使用したことがある場合は、`Placeholder` または `tf.Sesssion` をまったく定義する必要がないことに気づくでしょう。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "wfeKf0Nr1OEK"
      },
      "source": [
        "### Python 関数をグラフに変換する\n",
        "\n",
        "TensorFlow で記述するすべての関数には、組み込みの TF 演算と、`if-then` 句、ループ、`break`、`return`、`continue` などの Python ロジックが含まれます。TensorFlow 演算は `tf.Graph` で簡単にキャプチャされますが、Python 固有のロジックがグラフの一部となるには、さらにステップが必要となります。`tf.function` は、Python コードをグラフが生成するコードに変換するために、AutoGraph（`tf.autograph`）というライブラリを使用しています。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "PFObpff1BMEb"
      },
      "outputs": [],
      "source": [
        "def my_function(x):\n",
        "  if tf.reduce_sum(x) <= 1:\n",
        "    return x * x\n",
        "  else:\n",
        "    return x-1\n",
        "\n",
        "a_function = tf.function(my_function)\n",
        "\n",
        "print(\"First branch, with graph:\", a_function(tf.constant(1.0)).numpy())\n",
        "print(\"Second branch, with graph:\", a_function(tf.constant([5.0, 5.0])).numpy())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "hO4DBUNZBMwQ"
      },
      "source": [
        "直接グラフを閲覧する必要があることはほぼありませんが、正確な結果を確認するために出力を検査することは可能です。簡単に読み取れるものではありませんので、精査する必要はありません！"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "lAKaat3w0gnn"
      },
      "outputs": [],
      "source": [
        "# This is the graph-generating output of AutoGraph.\n",
        "print(tf.autograph.to_code(simple_relu))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "8x6RAqza1UWf"
      },
      "outputs": [],
      "source": [
        "# Don't read the output too carefully.\n",
        "print(tf.autograph.to_code(my_function))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "GZ4Ieg6tBE6l"
      },
      "source": [
        "ほとんどの場合、`tf.function` の動作に特別な考慮はいりませんが、いくつかの注意事項があり、これについては [tf.function ガイド](./function.ipynb)のほか、[詳細な Autograph リファレンス](https://github.com/tensorflow/tensorflow/blob/master/tensorflow/python/autograph/g3doc/reference/index.md)が役立ちます。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sIpc_jfjEZEg"
      },
      "source": [
        "### ポリモーフィズム: 1 つの `Function` で複数のグラフを得る\n",
        "\n",
        "`tf.Graph` は特定の型の入力（特定の [`dtype`](https://www.tensorflow.org/api_docs/python/tf/dtypes/DType) のテンソルまたは同じ [`id()` のオブジェクト](https://docs.python.org/3/library/functions.html#id%5D)など）に特化しています。\n",
        "\n",
        "`Function` を新しい `dtype` と形状の引数を使って呼び出すたびに、`Function` は新しい引数に対する新しい `tf.Graph` を作成します。`tf.Graph` の入力の `dtypes` と形状は**入力シグネチャ**または単に**シグネチャ**と呼ばれます。\n",
        "\n",
        "`Function` はそのシグネチャに対応する `tf.Graph` を `ConcreteFunction` に格納します。<strong data-md-type=\"double_emphasis\">`ConcreteFunction` は `tf.Graph` を囲むラッパーです。</strong>\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "LOASwhbvIv_T"
      },
      "outputs": [],
      "source": [
        "@tf.function\n",
        "def my_relu(x):\n",
        "  return tf.maximum(0., x)\n",
        "\n",
        "# `my_relu` creates new graphs as it sees more signatures.\n",
        "print(my_relu(tf.constant(5.5)))\n",
        "print(my_relu([1, -1]))\n",
        "print(my_relu(tf.constant([3., -3.])))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "1qRtw7R4KL9X"
      },
      "source": [
        "`Function` がそのシグネチャですでに呼び出されている場合、`Function` は新しい `tf.Graph` を作成しません。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "TjjbnL5OKNDP"
      },
      "outputs": [],
      "source": [
        "# These two calls do *not* create new graphs.\n",
        "print(my_relu(tf.constant(-2.5))) # Signature matches `tf.constant(5.5)`.\n",
        "print(my_relu(tf.constant([-1., 1.]))) # Signature matches `tf.constant([3., -3.])`."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "UohRmexhIpvQ"
      },
      "source": [
        "複数のグラフでサポートされているため、`Function` は**ポリモーフィック**です。そのため、単一の `tf.Graph` が表現できる以上の入力型をサポートし、パフォーマンスが改善されるように `tf.Graph` ごとに最適化することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "dxzqebDYFmLy"
      },
      "outputs": [],
      "source": [
        "# There are three `ConcreteFunction`s (one for each graph) in `my_relu`.\n",
        "# The `ConcreteFunction` also knows the return type and shape!\n",
        "print(my_relu.pretty_printed_concrete_signatures())"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "V11zkxU22XeD"
      },
      "source": [
        "## `tf.function` を使用する\n",
        "\n",
        "ここまでで、`tf.function` をデコレータまたはラッパーとして使用するだけで、Python 関数をグラフに変換できることを理解しました。しかし実際には、`tf.function` を正しく動作させるにはコツがいります！以下のセクションでは、`tf.function` を使って期待通りにコードを動作させるようにする方法を説明します。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "yp_n0B5-P0RU"
      },
      "source": [
        "### Graph execution と Eager execution\n",
        "\n",
        "`Function` 内のコードは、Eager と Graph の両方で実行できますが、デフォルトでは、`Function` は Graph としてコードを実行するようになっています。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_R0BOvBFxqVZ"
      },
      "outputs": [],
      "source": [
        "@tf.function\n",
        "def get_MSE(y_true, y_pred):\n",
        "  sq_diff = tf.pow(y_true - y_pred, 2)\n",
        "  return tf.reduce_mean(sq_diff)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "zikMVPGhmDET"
      },
      "outputs": [],
      "source": [
        "y_true = tf.random.uniform([5], maxval=10, dtype=tf.int32)\n",
        "y_pred = tf.random.uniform([5], maxval=10, dtype=tf.int32)\n",
        "print(y_true)\n",
        "print(y_pred)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "07r08Dh158ft"
      },
      "outputs": [],
      "source": [
        "get_MSE(y_true, y_pred)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "cyZNCRcQorGO"
      },
      "source": [
        "`Function` のグラフがそれに相当する Python 関数と同じように計算していることを確認するには、`tf.config.run_functions_eagerly(True)` を使って Eager で実行することができます。これは、通常どおりコードを実行するのではなく、<strong data-md-type=\"double_emphasis\">グラフを作成して実行する `Function` の能力をオフにする</strong>スイッチです。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "lKoF6NjPoI8w"
      },
      "outputs": [],
      "source": [
        "tf.config.run_functions_eagerly(True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "9ZLqTyn0oKeM"
      },
      "outputs": [],
      "source": [
        "get_MSE(y_true, y_pred)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "cV7daQW9odn-"
      },
      "outputs": [],
      "source": [
        "# Don't forget to set it back when you are done.\n",
        "tf.config.run_functions_eagerly(False)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "DKT3YBsqy0x4"
      },
      "source": [
        "ただし、Eager execution と Graph execution では `Function` の動作が異なることがあります。Python の [`print`](https://docs.python.org/3/library/functions.html#print) 関数がその例です。関数に `print` ステートメントを挿入して、それを繰り返し呼び出すとどうなるかを見てみましょう。\n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "BEJeVeBEoGjV"
      },
      "outputs": [],
      "source": [
        "@tf.function\n",
        "def get_MSE(y_true, y_pred):\n",
        "  print(\"Calculating MSE!\")\n",
        "  sq_diff = tf.pow(y_true - y_pred, 2)\n",
        "  return tf.reduce_mean(sq_diff)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "3sWTGwX3BzP1"
      },
      "source": [
        "何が出力されるか観察しましょう。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "3rJIeBg72T9n"
      },
      "outputs": [],
      "source": [
        "error = get_MSE(y_true, y_pred)\n",
        "error = get_MSE(y_true, y_pred)\n",
        "error = get_MSE(y_true, y_pred)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "WLMXk1uxKQ44"
      },
      "source": [
        "この出力に驚きましたか？**`get_MSE` は *3 回*呼び出されたにもかかわらず、出力されたのは 1 回だけでした。**\n",
        "\n",
        "説明すると、`print` ステートメントは `Function` が「[トレーシング](function.ipynb#tracing)」というプロセスでグラフを作成するために元のコードを実行したときに実行されます。<strong data-md-type=\"double_emphasis\">トレーシングは TensorFlow 演算をグラフにキャプチャしますが、グラフには `print` はキャプチャされません。</strong>以降、そのグラフは **Python コードを再実行せずに**、3 つのすべての呼び出しに対して実行されます。\n",
        "\n",
        "サニティーチェックとして、Graph execution をオフにして比較してみましょう。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "oFSxRtcptYpe"
      },
      "outputs": [],
      "source": [
        "# Now, globally set everything to run eagerly\n",
        "tf.config.experimental_run_functions_eagerly(True)\n",
        "print(\"Run all functions eagerly.\")\n",
        "\n",
        "# First, trace the model, triggering the side effect\n",
        "polymorphic_function = tf.function(model)\n",
        "\n",
        "# It was traced...\n",
        "print(polymorphic_function.get_concrete_function(input_data))\n",
        "\n",
        "# But when you run the function again, the side effect happens (both times).\n",
        "result = polymorphic_function(input_data)\n",
        "result = polymorphic_function(input_data)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "qYxrAtvzNgHR"
      },
      "outputs": [],
      "source": [
        "# Observe what is printed below.\n",
        "error = get_MSE(y_true, y_pred)\n",
        "error = get_MSE(y_true, y_pred)\n",
        "error = get_MSE(y_true, y_pred)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "_Df6ynXcAaup"
      },
      "outputs": [],
      "source": [
        "tf.config.run_functions_eagerly(False)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "PUR7qC_bquCn"
      },
      "source": [
        "`print` は *Python の副作用*です。[違いはほかにもあり](function#limitations)、関数を `Function` に変換する場合には注意が必要です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "oTZJfV_tccVp"
      },
      "source": [
        "注意: Eager execution と Graph execution の両方で値を出力する場合は、代わりに `tf.print` を使用してください。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "def6MupG9R0O"
      },
      "source": [
        "###`tf.function` のベストプラクティス\n",
        "\n",
        "`Function` の動作に慣れるまで、しばらく時間がかかるかもしれませんが、その時間を短縮するには、トイ関数に `@tf.function` をデコレートしていろいろ試しながら、Eager から Graph execution に切り替える経験を積むと良いでしょう。\n",
        "\n",
        "グラフ対応の TesorFlow プログラムを記述するには、*`tf.function` 向けにデザインする*のが一番かもしれません。その際のヒントをいくつか紹介します。\n",
        "\n",
        "- 早い段階で Eager execution と Graph execution を切り替えながら、2 つのモードで異なる結果を得るかどうか、またはそのタイミングを知るために `tf.config.run_functions_eagerly` を頻繁に使用しましょう。\n",
        "- Python 関数の外で `tf.Variable` を作成し、Python 関数の中でそれを変更するようにします。これは、`keras.layers`、`keras.Model`、`tf.optimizers` などの `tf.Variable` を使用するオブジェクトでも同じです。\n",
        "- [外側の Python 変数に依存する](function#depending_on_python_global_and_free_variables)関数を記述しないようにしましょう。ただし、`tf.Variables` と Keras オブジェクトについては例外です。\n",
        "- テンソルとほかの TensorFlow の型を入力として取る関数を記述するようにしましょう。ほかの型のオブジェクトを渡すことは可能ですが、[十分な注意が必要です](function#depending_on_python_objects)！\n",
        "- パフォーマンスを最大限に得るには、`tf.function` の下にできるだけ多くの計算を含めるようにしましょう。たとえば、トレーニングステップ全体またはトレーニングループ全体をデコレートすることができます。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "ViM3oBJVJrDx"
      },
      "source": [
        "## 高速化の確認"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "A6NHDp7vAKcJ"
      },
      "source": [
        "コードのパフォーマンスは通常、`tf.function` によって改善されますが、改善率は実行する計算によって異なります。 小さな計算であれば、グラフ呼び出しのオーバーヘッドに制約を受ける可能性があります。パフォーマンスの変化は、次のようにして確認することができます。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "jr7p1BBjauPK"
      },
      "outputs": [],
      "source": [
        "x = tf.random.uniform(shape=[10, 10], minval=-1, maxval=2, dtype=tf.dtypes.int32)\n",
        "\n",
        "def power(x, y):\n",
        "  result = tf.eye(10, dtype=tf.dtypes.int32)\n",
        "  for _ in range(y):\n",
        "    result = tf.matmul(x, result)\n",
        "  return result"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "ms2yJyAnUYxK"
      },
      "outputs": [],
      "source": [
        "print(\"Eager execution:\", timeit.timeit(lambda: power(x, 100), number=1000))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "gUB2mTyRYRAe"
      },
      "outputs": [],
      "source": [
        "power_as_graph = tf.function(power)\n",
        "print(\"Graph execution:\", timeit.timeit(lambda: power_as_graph(x, 100), number=1000))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "Q1Pfo5YwwILi"
      },
      "source": [
        "トレーニングループの高速化には、一般的に `tf.function` が使用されます。Keras を使った例は[こちら](keras/writing_a_training_loop_from_scratch#speeding-up_your_training_step_with_tffunction)をご覧ください。\n",
        "\n",
        "注意: パフォーマンスをさらに大きく改善させるには、[`tf.function(jit_compile=True)`](https://www.tensorflow.org/xla#explicit_compilation_with_tffunctionjit_compiletrue) を使用することもできます。特に、コードで大量の TF 制御フローが使用されており、小さなテンソルが多数使用されている場合に最適です。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "sm0bNFp8PX53"
      },
      "source": [
        "### パフォーマンスとトレードオフ\n",
        "\n",
        "グラフを使ってコードを高速化することは可能ですが、グラフを作成するプロセスにはオーバーヘッドが伴います。一部の関数の場合、グラフの作成にはグラフを実行するよりも長い時間が掛かることがあります。**このオーバーヘッドは、以降の実行においてパフォーマンスが向上するのであれば挽回することができますが、大規模なモデルトレーニングの最初の数ステップではトレーシングにより速度が減少する可能性があることに注意してください。**\n",
        "\n",
        "モデルの規模に関係なく、頻繁にトレースするのは避けたほうがよいでしょう。`tf.function` ガイドでは、リトレーシングを回避できるよう、[入力仕様を設定してテンソル引数を使用する方法](function#controlling_retracing)が説明されています。パフォーマンスが異常に低下している場合は、リトレーシングをうっかり行っていないかどうかを確認することをお勧めします。"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "F4InDaTjwmBA"
      },
      "source": [
        "## `Function` がトレーシングしているタイミングを確認するには\n",
        "\n",
        "`Function` がトレーシングしているタイミングを確認するには、コードに `print` ステートメントを追加すれば、`Function` がトレーシングを行うたびに `print` ステートメントが実行されるようになります。"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "hXtwlbpofLgW"
      },
      "outputs": [],
      "source": [
        "@tf.function\n",
        "def a_function_with_python_side_effect(x):\n",
        "  print(\"Tracing!\") # An eager-only side effect.\n",
        "  return x * x + tf.constant(2)\n",
        "\n",
        "# This is traced the first time.\n",
        "print(a_function_with_python_side_effect(tf.constant(2)))\n",
        "# The second time through, you won't see the side effect.\n",
        "print(a_function_with_python_side_effect(tf.constant(3)))"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {
        "id": "inzSg8yzfNjl"
      },
      "outputs": [],
      "source": [
        "# This retraces each time the Python argument changes,\n",
        "# as a Python argument could be an epoch count or other\n",
        "# hyperparameter.\n",
        "print(a_function_with_python_side_effect(2))\n",
        "print(a_function_with_python_side_effect(3))"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "rtN8NW6AfKye"
      },
      "source": [
        "上記を実行すると、余分なトレーシングが確認されますが、これは新しい Paython 引数が常に新しいグラフの作成をトリガーしているためです。\n"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {
        "id": "D1kbr5ocpS6R"
      },
      "source": [
        "## 次のステップ\n",
        "\n",
        "より詳しい説明については、`tf.function` API リファレンスページと[ガイド](./function.ipynb)を参照してください。"
      ]
    }
  ],
  "metadata": {
    "colab": {
      "collapsed_sections": [],
      "name": "intro_to_graphs.ipynb",
      "toc_visible": true
    },
    "kernelspec": {
      "display_name": "Python 3",
      "name": "python3"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 0
}
